#include "face_detect.h"

#define LOG_TAG "main.cpp"
#include "utils.h"
#include <stdlib.h>

#define IMG_DEFAULT_BIG  176

static CvHaarClassifierCascade* mFaceCascade = NULL;
static CvCapture *mCvCapture = NULL;
static IplImage *mFrame = NULL;
char *mCascadeFile = "/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt2.xml";

CvSize getCaptureSize(CvCapture *capture)
{
    CvSize sz;
	sz.width = (int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
	sz.height = (int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);
    LOGD("capture size: %dx%d", sz.width, sz.height);
	return sz;
}

void myCvReleaseImage(IplImage **img)
{
    cvReleaseImage(img);
    *img = NULL;
}

void optimal_size(int in[], int out[])
{
    float ratio = ((float) in[0]) / in[1];
    //LOGD("input ratio: %f", ratio);
    if(in[0] == in[1]){
        out[0] = out[1] = (int) IMG_DEFAULT_BIG;
        return;
    }

    if(in[0] > in[1]){
        out[0] = (int) (IMG_DEFAULT_BIG * ratio);
        out[1] = (int) (IMG_DEFAULT_BIG);
    } else {
        out[0] = (int) (IMG_DEFAULT_BIG);
        out[1] = (int) (IMG_DEFAULT_BIG * ratio);
    }

}

IplImage * resizeImage(const IplImage *srcImg) 
{
    int origSize[2], smallSize[2];
    origSize[0] = srcImg->width; origSize[1] = srcImg->height;
    //    LOGD("src: %d x %d", origSize[0], origSize[1]);
    optimal_size(origSize, smallSize);

    IplImage *tmp2 = cvCreateImage(cvSize(smallSize[0], smallSize[1]), srcImg->depth, srcImg->nChannels);
    IplImage *tmp1 = cvCreateImage(cvSize(smallSize[0], smallSize[1]), IPL_DEPTH_8U, 1);

    //resize
    cvResize(srcImg, tmp2, CV_INTER_CUBIC);
    //cvt color
    cvCvtColor(tmp2, tmp1, CV_BGR2GRAY);

    myCvReleaseImage(&tmp2);
    return (tmp1);
}

int main(int argc, char** argv)
{
    IplImage *mOrigFrame = NULL;
    IplImage *resizedImg = NULL;
    IplImage *detectedImg = NULL;
    IplImage *faceNotFoundImg = NULL;
    IplImage *thresholdedImg = NULL;    //二级化
    IplImage *histogramEqualizatedImg = NULL; //histogram equalization

    IplImage *yuvImg = NULL;
    IplImage *maskImage = NULL;
    //these channels some times stands for R,G,B or Y,Cr,Cb channel
    IplImage *channel_0 = NULL;
    IplImage *channel_1 = NULL;
    IplImage *channel_2 = NULL;

    CvRect faceRect;

    for(int i =0; i < argc; i++){
        LOGD("argv[%d] = %s", i, argv[i]);
    }
    switch (argc) {
        case 2:
            mCascadeFile = argv[1];
        case 3:
            ;
        default:
            break;
    }

    mCvCapture = cvCreateCameraCapture(CV_CAP_ANY);

    mFrame = cvCreateImage(getCaptureSize(mCvCapture), IPL_DEPTH_8U, 3);  
    DUMP_IMAGE(mFrame);
    yuvImg = cvCreateImage(cvGetSize(mFrame), mFrame->depth, mFrame->nChannels);
    DUMP_IMAGE(yuvImg);
    faceNotFoundImg = cvLoadImage("./face_not_found.bmp");
    DUMP_IMAGE(faceNotFoundImg);
    maskImage = cvCreateImage(cvGetSize(mFrame), IPL_DEPTH_8U, 1);
    DUMP_IMAGE(maskImage);
    channel_0 = cvCreateImage(cvGetSize(mFrame), IPL_DEPTH_8U, 1);
    DUMP_IMAGE(channel_0);
    channel_1 = cvCreateImage(cvGetSize(mFrame), IPL_DEPTH_8U, 1);
    channel_2 = cvCreateImage(cvGetSize(mFrame), IPL_DEPTH_8U, 1);

    // Create a window in which the captured images will be presented
    //cvNamedWindow( "window_0", CV_WINDOW_AUTOSIZE );
    cvNamedWindow("window_1", CV_WINDOW_AUTOSIZE);
    cvNamedWindow("window_2", CV_WINDOW_AUTOSIZE);
    cvMoveWindow("window_1", 600, 100);

DURATION_START;
    mFaceCascade = (CvHaarClassifierCascade*)cvLoad(mCascadeFile, 0, 0, 0 );
DURATION_STOP("load cascade file");
    
    int frame_count = 0;
    bool detect_res = false;
    float scale_ratio = 0;
    

    duration_start();
    for(; ; frame_count ++) {
        mOrigFrame= cvQueryFrame(mCvCapture);
        if (mOrigFrame) {
            LOGD("capture %d frame", frame_count);
            cvCopy(mOrigFrame, mFrame);
        }

        if(mFrame->origin == IPL_ORIGIN_BL) {
            LOGD("need FLIP");
            cvFlip(mFrame, mFrame, 0);
        }

        //cvShowImage("window_0", mFrame);

        cvZero(maskImage);
        cvCvtColor(mFrame, yuvImg, CV_BGR2YCrCb);

        cvSetImageCOI(yuvImg,2);//channel Cr
        cvCopy(yuvImg, channel_1);
        cvSetImageCOI(yuvImg, 3);//channel Cb
        cvCopy(yuvImg, channel_2);
        cvSetImageCOI(yuvImg,0);//reset

        for(int i = 0; i < mFrame->height; i++) {
            for(int j = 0; j < mFrame->width; j ++) {
                if( ((unsigned char *)(channel_1->imageData + i * channel_1->widthStep))[j] >= 123
                 && ((unsigned char *)(channel_1->imageData + i * channel_1->widthStep))[j] <= 175 
                 && ((unsigned char *)(channel_2->imageData + i * channel_2->widthStep))[j] >= 93
                 && ((unsigned char *)(channel_2->imageData + i * channel_2->widthStep))[j] <= 133) {

                    ((unsigned char *)(maskImage->imageData + i * maskImage->widthStep))[j] = 255;
                 }
            }
        }

        cvShowImage("window_1", mFrame);
        cvCopy(mFrame, yuvImg, maskImage);
        //cvShowImage("window_2", yuvImg);
        cvShowImage("window_2", maskImage);



        //resizedImg = resizeImage(mFrame);
        //scale_ratio = ((float) (mFrame->width)) / resizedImg->width;
        //LOGD("scale_ratio = %f", scale_ratio);
        
/*
//DURATION_START;
        detect_res = face_detect(resizedImg, mFaceCascade, &faceRect);
//DURATION_STOP("face_detect");

        if(detect_res){
            //LOGD("detected zone:(%d,%d) with %dx%d", faceRect.x, faceRect.y, faceRect.width, faceRect.height);
            detectedImg = cvCreateImage(cvSize(faceRect.width, faceRect.height), IPL_DEPTH_8U, 1);
            cvSetImageROI(resizedImg, faceRect);
            cvResize(resizedImg, detectedImg);
            cvResetImageROI(resizedImg);

            thresholdedImg = cvCreateImage(cvGetSize(detectedImg), detectedImg->depth, detectedImg->nChannels);
            histogramEqualizatedImg = cvCreateImage(cvGetSize(detectedImg), detectedImg->depth, detectedImg->nChannels);
            cvThreshold(detectedImg, thresholdedImg, 80, 255, CV_THRESH_BINARY);    //二级化``
            cvEqualizeHist(detectedImg, histogramEqualizatedImg);

            cvShowImage("window_1", histogramEqualizatedImg);
            
            cvReleaseImage(&resizedImg);
            cvReleaseImage(&detectedImg);
            cvReleaseImage(&thresholdedImg);
            cvReleaseImage(&histogramEqualizatedImg);
        }else{
            //LOGD("face NOT founded");
            cvShowImage("window_1", faceNotFoundImg);
        }
*/

        //press 'esc' to stop
        if ( (cvWaitKey(5) & 255) == 27 ) break;

        if(frame_count % 5 == 0) {
            LOGD("frame rate:%f", ((float) 5) / duration_stop() * 1000/*ms*/);
            duration_start();
        }
    }
    
    //cvDestroyWindow("window_0");
    cvDestroyWindow("window_1");
    cvReleaseCapture(&mCvCapture);
    return 0;
}

